// RMSThread.cpp: implementation of the CRMSThread class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "RMSThread.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define MAGIC 0x12345678

extern DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	CRMSThread* pRMSThread = (CRMSThread*)lpParameter;

	if(!pRMSThread)
		return 0;

	// check that thread was not deleted (should not happen)
	if(pRMSThread->MAGIC_H != MAGIC)
		return 0;

	pRMSThread->m_result = pRMSThread->ThreadFunc();

	// set "thread is terminated flag" (new)
	CloseHandle(pRMSThread->m_hThread);
	pRMSThread->m_hThread = 0;
	pRMSThread->m_bTerminated = TRUE; 
	pRMSThread->m_bQuit = FALSE;

	SetEvent(pRMSThread->m_stopEvent);

	return pRMSThread->m_result;
}


CRMSThread::CRMSThread()
{
	m_bTerminated = TRUE;
	m_bQuit = FALSE;
	m_hThread = NULL;
	MAGIC_H = MAGIC;

	m_stopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
}

CRMSThread::~CRMSThread()
{
	Terminate(FALSE);
	MAGIC_H = 0;
}

BOOL CRMSThread::Execute()
{
	if(m_hThread)
		return FALSE;

	m_bTerminated = FALSE;
	m_bQuit = FALSE;
	m_dwID = 0;

	m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, this, 0, &m_dwID);

	TRACE2("%x - CRMSThread::Execute() - thread: %x\n", this, m_dwID);

    return (m_hThread == NULL);
}

DWORD CRMSThread::OnTerminate()
{
	return DEFAULT_TERMINATION_TIMEOUT;
}

void CRMSThread::OnCriticalTerminate()
{
}

DWORD CRMSThread::Terminate(BOOL bCritical)
{
	TRACE("%x - CRMSThread::Terminate(), m_bQuit=%i - thread:%#x, calling thread:%#x\n", this, m_bQuit, m_dwID, GetCurrentThreadId());

	if(m_bTerminated || m_bQuit || (m_hThread == NULL))
		return 0;

	m_bQuit = TRUE;

	// call object termination actions of the inherited class
	DWORD dwMilliseconds = OnTerminate();

	if(::WaitForSingleObject(m_stopEvent, dwMilliseconds) != WAIT_OBJECT_0)
	{
		// call critical object termination actions of the inherited class
		OnCriticalTerminate();

		do
		{
			TerminateThread(m_hThread, (DWORD)-1);
			Sleep(5);
			GetExitCodeThread(m_hThread, &m_result);
		}
		while(m_result == STILL_ACTIVE);
	}

	if(m_hThread) CloseHandle(m_hThread);
	m_hThread = NULL;
	m_bTerminated = TRUE;

	return m_result;
}
